/* Copyright 2017, 2018, 2019, 2020 Gabriel Czernikier
 * Portions listed below copyrighted to the Linux Kernel copyright holders.
 *
 * This file is part of Côtehaus.
 * Côtehaus is free software: counted out an exception on the Linux Kernel code portions,
 * you can redistribute it and/or modify
 * it under the terms of one of the following:
 * 1. The same dual license as that of Côtehaus itself, of which individual licenses are
 * the MIT License and the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 2. The MIT License.
 * 3. The GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * Côtehaus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * MIT License and the GNU General Public License for more details.
 * You should have received a copy of the MIT License and the GNU General Public License
 * along with Côtehaus.  If not, see <https://opensource.org/licenses/MIT> and <http://www.gnu.org/licenses/>.
 *
 * Portions of code copied from the Linux Kernel are those of struct list_head and macros LIST_HEAD_INIT, LIST_HEAD, INIT_LIST_HEAD and list_entry.
 * The Linux Kernel version of origin is 2.4. The file of origin is include/linux/list.h in the Linux source tree.
 * The code capture was made via the Linux Kernel 2.4 Internals book, from which specific section is 2.4, "Linux linked list implementation" (https://www.tldp.org/LDP/lki/lki-2.html#ss2.4).
 * Regardless of the fact the copied code could have been altered, the original code's license overrides Côtehaus' one whenever applicable. Macros defined in this file are generally derived work from the aforementioned origin, implying as a reasonable outcome that the above license override statement applied also for them.
 */

#ifndef __CH_TYPES_H
#define __CH_TYPES_H
#include <stdint.h>
#include <stdlib.h>
struct list_head {
struct list_head *next, *prev;
};
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
#define INIT_LIST_HEAD(ptr) do { \
(ptr)->next = ptr; (ptr)->prev = ptr; \
} while (0)
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = (pos)->next)
#define list_for_each_entry(entry_ptr, type, member, head) \
for (entry_ptr = (head)->next!=(head) ? list_entry((head)->next, type, member) : NULL; (entry_ptr)!=NULL; entry_ptr = (entrt_ptr)->member.next!=(head) ? list_entry((entrt_ptr)->member.next, type, member) : NULL)
#define range_for_each(pos, first, last) \
for (pos = first; (pos) != (last); pos = (pos)->next)
#define range_for_each_entry(entry_ptr, type, member, first, last) \
for (entry_ptr = (first)!=(last) ? list_entry(first, type, member) : NULL; (entry_ptr)!=NULL; entry_ptr = (entrt_ptr)->member.next!=(last) ? list_entry((entrt_ptr)->member.next, type, member) : NULL)
#define list_peek_entry(type, member, head) \
(head)->next!=(head) ? list_entry((head)->next, type, member) : NULL;
#define list_peek_next_entry(entry_ptr, type, member, head) \
(entry_ptr)->member.next!=(head) ? list_entry((entry_ptr)->member.next, type, member) : NULL;
#define list_add(ptr, head) do { \
(ptr)->next = (head)->next; (head)->next = ptr; (ptr)->prev = head; (ptr)->next->prev = ptr; \
} while(0)
#define list_add_tail(ptr, head) do { \
(ptr)->prev = (head)->prev; (head)->prev = ptr; (ptr)->next = head; (ptr)->prev->next = ptr; \
} while(0)
#define list_del(ptr) do { \
(ptr)->next->prev = (ptr)->prev; (ptr)->prev->next = (ptr)->next; \
} while(0)
// Gets the first element from a list, removes it, and derreferences the original entry,
#define list_pop_entry(entry_ptr, head, type, member) do { \
	if((head)->next==(head)) { \
		entry_ptr = NULL; \
	} \
	else { \
		entry_ptr = list_entry((head)->next, type, member); \
		list_del((head)->next); \
	} \
} while(0)

struct size_data {
	size_t size;
	void *data;
	struct list_head size_data_list;
	void(*data_pack_fnc)(void *(*write_fnc)(void *src, size_t n), struct size_data *for_pack);
};
struct size_data *for_ubyte_array(struct size_data **sd, size_t n);
struct size_data *for_uint16_t(struct size_data **sd);
struct size_data *for_uint32_t(struct size_data **sd);
struct size_data *for_lengthed_wide_sequence(struct size_data **sd, size_t n);
struct size_data *for_generic_ptr(struct size_data **sd);
int lengthed_wide_sequence_compar_adapt(const void *s1, const void *s2);
#endif
